package BO.SimpleIRC
{
	import flash.net.Socket;
	import flash.events.Event;
	
	import flash.errors.*;
	import flash.events.*;
	import flash.net.Socket;
	
	public class IRC
	{
		private var isConnect:Boolean;
		private var server:String;
		private var port:int;
		private var con:Socket;
		private var encoding:String;
		private var nick:String;
		
		private var name:String;
		private var host:String;
		private var user:String;
		private var realName:String;
		
		private var readBuffer:String;
		
		private var sayListener:Function;
		private var connectListener:Function;
		
		public function IRC(server:String, port:int, enc:String){
			con = new Socket();
			encoding = enc;
			this.server = server;
			this.port = port;
			this.isConnect = false;
		}
		
		public function setOnSayEvent(listener:Function) : void{
			this.sayListener = listener;
		}
		public function setOnConnect(listener:Function) : void{
			this.connectListener = listener;
		}
		
		public function connect(name:String, host:String, user:String, realName:String, nick:String, enc:String):void{
			this.nick = nick;
			this.encoding = enc;
			this.name = name;
			this.host = host;
			this.user = user;
			this.realName = realName;
			readBuffer = "";
			con.addEventListener(Event.CONNECT, init);
			con.addEventListener(ProgressEvent.SOCKET_DATA, socketDataHandler);
			con.addEventListener(Event.CLOSE, closeHandler);
			con.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
	        con.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
	        try{
				con.connect(this.server, this.port);
	        }catch(error:Error){
	        	trace(error.message+"\n");
	        	con.close();
	        }
			trace(this.server + ":"+this.port+" connect...");
		}
		private function init(e:Event) : void{
			trace("init...\n");
		}
		
		private function writeln(str:String):void{
			trace(str);
			try{
				con.writeMultiByte(str+"\r\n", encoding);
				con.flush();
			}catch(e:IOError){
				trace(e);
			}
		}
		public function say(channel:String, str:String) : void{
			this.writeln("PRIVMSG "+channel+" :"+str);
		}
		public function notice(channel:String, str:String) : void{
			this.writeln("NOTICE "+channel+" "+str);
		}
		public function join(channel:String): void {
			this.writeln("JOIN "+channel);
		}
		public function part(channel:String): void {
			this.writeln("PART "+channel);
		}
		public function topic(channel:String, topic:String = null) : void{
			var topicStr:String = "TOPIC "+channel;
			if(topic != null) topicStr += " "+topic;
			this.writeln(topicStr);
		}
		public function quit(): void{
			this.writeln("quit");
		}
		
		private function socketDataHandler(event:ProgressEvent):void {
        	this.readBuffer += con.readMultiByte(con.bytesAvailable, this.encoding);
        	var ind:int = -1;
        	while((ind = this.readBuffer.indexOf("\r\n")) != -1){
        		this.readMsg(this.readBuffer.substring(0, ind));
        		this.readBuffer = this.readBuffer.substr(ind+2);
        	}
    	}
    	private function readMsg(str:String) : void {
    		if(!isConnect){
    			this.connectIRC();
    		}else{
    			parseMsg(str);
    		}
    	}
    	private function commandParse(cmdStr:String): Object{
    		var sp:int = cmdStr.indexOf(' ');
			var cmd:String = cmdStr.substring(0, sp);
			var stp:int = cmdStr.charAt(sp+1) == ':' ? 2 : 1;
			var param:Array = cmdStr.substr(sp+stp).split(' :');
			return {"cmd":cmd, "param":param};
    	}
    	private function parseMsg(str:String) : void{
    		var nick:String;
    		var cmd:String;
    		var param:Array;
    		
    		var oCmd:Object;
    		if(str.charAt(0) != ':'){
    			oCmd = commandParse(str);
    			cmd = oCmd.cmd;
    			param = oCmd.param;
    		}else{
    			var sp:int = str.indexOf(' ');
    			var prefix:String = str.substring(1, sp);
    			var up:int = prefix.indexOf('!');
    			nick = up == -1 ? prefix : prefix.substring(0, up);
    			trace(prefix + "["+up+"]");
    			var cmdstr:String = str.substr(sp+1);
    			oCmd = commandParse(cmdstr);
    			cmd = oCmd.cmd;
    			param = oCmd.param;
    		}
    		/* 
    		trace("nick = "+nick + ", cmd = "+cmd);
    		for each(var p in param){
    			trace(p);
    		}
    		 */
    		switch(cmd){
    			case "PING":
    				this.writeln("PONG :"+param[0]);
    				break;
    			case "PRIVMSG":
    			case "NOTICE":
    			trace(param[0]);
    				var channels:Array = param[0].split(', ');
    				this.sayListener({"nick":nick, "type":cmd, "channel":channels,"msg":param[1]});
    				break;
    			case "422":
	    			this.connectListener();
    				break;
    			default:
    				trace("["+str+"]");
    		}
    	}
    	private function command(cmd:String, param:String):void{
    		
    	}
    	private function connectIRC() : void {
    		this.writeln("NICK "+nick);
			this.writeln("USER "+name+" \""+host+"\" \""+user+"\" :"+realName);
			this.isConnect = true;
    	}
	    private function ioErrorHandler(event:IOErrorEvent):void {
	        trace("ioErrorHandler: " + event);
	    }
	
	    private function securityErrorHandler(event:SecurityErrorEvent):void {
	        trace("securityErrorHandler: " + event);
	    }
	    private function closeHandler(event:Event):void {
	        trace("closeHandler: " + event);
	    }
	}
}